/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/*
 * VariableTypeRenderer.java
 *
 * Created on Jun 13, 2010, 4:28:07 PM
 */

package org.netbeans.modules.javafx.debugger.tablerendering;

import com.sun.javafx.jdi.FXSequenceReference;
import com.sun.javafx.jdi.FXSequenceReference.Types;
import com.sun.javafx.jdi.FXValue;
import com.sun.jdi.Value;
import org.netbeans.api.debugger.jpda.Field;
import java.awt.Component;
import java.awt.Rectangle;
import java.util.HashMap;
import javax.swing.JTable;
import javax.swing.table.TableCellRenderer;
import org.netbeans.modules.debugger.jpda.expr.JDIVariable;
import org.netbeans.modules.debugger.jpda.models.AbstractVariable;
import org.netbeans.modules.debugger.jpda.models.JPDAThreadImpl;
import org.openide.util.RequestProcessor;

/**
 *
 * @author Michal Skvor <michal.skvor at sun.com>
 */
public class VariableTypeRenderer extends javax.swing.JPanel implements TableCellRenderer {

    private Object o;
    
    private static final HashMap<String, String> types = new HashMap<String, String>();
    
    static {
        types.put( "int", "Integer" );
        types.put( "float", "Number" );
        types.put( "boolean", "Boolean" );
        types.put( "short", "Short" );
        types.put( "long", "Long" );
        types.put( "byte", "Byte" );
    }
    
    private RequestProcessor rp = new RequestProcessor( "", 5 );
    private boolean repaintCall = false;
    private int row, column;
    private JTable table;
    private TypeEvaluator typeEvaluator = new TypeEvaluator();
    
    /** Creates new form VariableTypeRenderer */
    public VariableTypeRenderer( Object o ) {
        this.o = o;
        initComponents();
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {
        java.awt.GridBagConstraints gridBagConstraints;

        labelValue = new javax.swing.JLabel();

        setLayout(new java.awt.GridBagLayout());

        labelValue.setText(org.openide.util.NbBundle.getMessage(VariableTypeRenderer.class, "VariableTypeRenderer.labelValue.text")); // NOI18N
        gridBagConstraints = new java.awt.GridBagConstraints();
        gridBagConstraints.gridx = 0;
        gridBagConstraints.gridy = 0;
        gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
        gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
        gridBagConstraints.weightx = 1.0;
        add(labelValue, gridBagConstraints);
    }// </editor-fold>//GEN-END:initComponents


    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JLabel labelValue;
    // End of variables declaration//GEN-END:variables

    public Component getTableCellRendererComponent( JTable table, Object value,
            boolean isSelected, boolean hasFocus, int row, int column)
    {
        this.table = table;
        this.row = row;
        this.column = column;
        
//        labelValue.setText( o.toString());
        if( o instanceof Field ) {
            if( !repaintCall ) {
                repaintCall = true;
                rp.post( typeEvaluator );
            } else {
                repaintCall = false;
            }
            
        }
        if( isSelected ) {
            setBackground( table.getSelectionBackground());
            setForeground( table.getSelectionForeground());
            labelValue.setBackground( table.getSelectionBackground());
            labelValue.setForeground( table.getSelectionForeground());
        } else {
            setBackground( table.getBackground());
            setForeground( table.getForeground());
            labelValue.setBackground( table.getBackground());
            labelValue.setForeground( table.getForeground());
        }

        return this;
    }
    
    private class TypeEvaluator implements Runnable {

        private void update() {
            repaintCall = true;
            Rectangle r = table.getCellRect( row, column, true );                   
            table.repaint( r );
        }
        
        public void run() {
            Field f = (Field)o;
            JDIVariable v = (JDIVariable)f;
            AbstractVariable av = (AbstractVariable)f;
            
            String fieldTypeName = f.getDeclaredType().replace( '$', '.' );
                                    
            if( types.containsKey( fieldTypeName )) {
                fieldTypeName = types.get( fieldTypeName );
            } else if( "com.sun.javafx.runtime.sequence.Sequence".equals( fieldTypeName )) {
                
                JPDAThreadImpl thread = (JPDAThreadImpl)av.getDebugger().getCurrentThread();  
                if( thread == null ) {
                    labelValue.setText( "No current thread." );
                    update();
                    return;
                }
                thread.accessLock.writeLock().lock();

                try {
                    if( !thread.isSuspended()) {
                        labelValue.setText( "No current thread." );
                        update();
                        return;
                    }                

                    Value oo = v.getJDIValue();
                    FXValue fxv = (FXValue)oo;
                    if( fxv instanceof FXSequenceReference ) {
                        FXSequenceReference seq = (FXSequenceReference)fxv;
                        Types seqType = seq.getElementType();
                        if( Types.INT.equals( seqType )) {
                            fieldTypeName = "Integer[]"; // NOI18N
                        } else if( Types.OTHER.equals( seqType )) {
                            fieldTypeName = "String[]"; // NOI18N
                        } else {
                            if( seqType != null ) {
                                String typeName = seqType.name().toLowerCase();
                                fieldTypeName = typeName.substring( 0, 1 ).toUpperCase() +
                                        typeName.substring( 1 ) + "[]"; // NOI18N
                            } else {
                                // FIXME: Why null value is here?                       
                                fieldTypeName = "null"; // 
                            }
                        }
                    }
                } finally {
                    thread.accessLock.writeLock().unlock();
                }    
            } 
            labelValue.setText( fieldTypeName );                    
            update();
        }
    }

}
